import type { serviceData } from './entity/entity';
import { GetStorage, Toast, ClearAll, ShowLoading, HideLoading } from './uni.public'


declare const uni: any;
declare global {
  interface Window {
    getPerformance: any;
  }
}

const MQ: { url: string; data: string; request: UniApp.RequestTask }[] = [];

/**
 * 失效后重定向
 */
const initLoad = () => {
  ClearAll()
  uni.redirectTo({ url: '/pages/index/index' })
  Toast("登录过期，请重新登录");
}


interface HTTPSEND {
  api_url: string,
  sendData: object,
  method?: "POST" | "GET",
  Loading?: boolean,
  dataAll?: boolean
}

interface PARAMETER {
  //数据请求中是否现在加载
  loading?: boolean;
  // 是否返回所有数据 默认 false
  dataAll?: boolean;
  verifyData?: boolean;
}



class RequestHttp {

  /**
   * 接口放行，不需要登录验证的接口如登录接口获取验证码接口
   */
  static Release: Array<string> = []

  /**
   * 业务成功状态码集合
   */
  static successCode: Array<number | string> = [200, "200", 1, '1', 0]

  /**
   * http 网络响应成功状态码
   */
  static HttpOkStatusCode: Array<number> = [200, 304]

  /**
   * http 请求参数配置
   * @param {*} api_url url 地址
   * @param {*} sendData 发送数据
   * @param {*} method 请求方式，默认 POTS
   * @param {*} Loading??  数据请求中是否现在加载
   * @param {*} dataAll??? 是否返回所有数据 默认 false
   * @param {*} verifyData url拦截重复请求是否包含参数在内
   */

  static req<T extends HTTPSEND>(api_url: string, sendData: object, method = "POST", Loading?: boolean, dataAll?: boolean, verifyData = false):Promise<serviceData | string> {

    const url: string = /^https?:\/\//i.test(api_url) ? api_url : `${api_url.includes('evaluate') ?
      import.meta.env.VITE_APP_BASE_URLAppraise : api_url.includes('ad_info') ? import.meta.env.VITE_APP_BASE_URLAd : import.meta.env.VITE_APP_BASE_URLApi}${api_url}`;

    console.log(url,api_url, sendData, method, Loading, dataAll, verifyData, '---------------', GetStorage('Startup'), url)

    return new Promise((resolve, reject) => {

      let start = Date.now();


      const is = MQ.find(u => verifyData ? u.url === url : u.url === url && u.data === JSON.stringify(sendData)),
        indexId = MQ.findIndex(u => u.url === url && u.data === JSON.stringify(sendData));

      if (is) {
        is.request?.abort();
        MQ.splice(indexId, 1)
      }


      // request 拦截器
      uni.addInterceptor('request', {
        invoke(args:UniApp.RequestOptions) { // 请求之前拦截
          // 部分接口放行
          if (RequestHttp.successCode.includes(GetStorage('Token'))) {
            if (!RequestHttp.Release.find((srt) => url.includes(srt))) {
              resolve(`该接${url}口需要token验证`);
            }
          }

          args.header={
            token: GetStorage('Startup')?.token
          }
        },
        success(args:UniApp.RequestSuccessCallbackResult) {  // 请求响应后拦截
          // 请求成功后，可以修改数据 下面的状态码字段取的  反正数据中的 code 如果没有在响应结果添加 code 字段，或者修改 code

        }
      })


      Loading && ShowLoading()
      const requestTask = uni.request({
        url: url,
        data: sendData,
        method,
        fail(err: Error) {
          Toast("网络请求失败");
        },
        success(response: UniApp.RequestSuccessCallbackResult) { //{ data: serviceData; statusCode: number; }
          const is = MQ.find(u => verifyData ? u.url === url : u.url === url && u.data === JSON.stringify(sendData))
          const indexId = MQ.findIndex(u => u.url === url && u.data === JSON.stringify(sendData))
          is && MQ.splice(indexId, 1)
          !response.data && Toast("接口报错，报文无data数据");
          // http、TCP ，IP 状态码判断
          Loading && HideLoading()
          if (response && RequestHttp.HttpOkStatusCode.includes(response.statusCode)) {
            const receiveData: serviceData = response.data as serviceData; // 后端返回数据

            //接口业务状态码判断
            switch (parseInt(receiveData.code)) {
              // 当请求返回是的状态码正确是才返回数据
              case 1:
              case 200:
                const dataBox = RequestHttp.success(receiveData)
                dataAll ? resolve(receiveData) : RequestHttp.successCode.includes(receiveData.code) && dataBox ? resolve(dataBox) : reject(receiveData)
                receiveData.data ? resolve(receiveData.data) : resolve(receiveData.data)
                break;
              case 500:
                if (receiveData.message && receiveData.message.includes('token过期')) {
                  initLoad()
                } else {
                  Toast(receiveData.message || `接口${url}响应异常`);
                  reject(response.data);
                }
                break;
              default:
                if (dataAll) {
                  resolve(receiveData)
                } else {
                  initLoad()
                  // 当所有数据返回时，错误提示由请求接口处理提示
                  dataAll == false && Toast(receiveData.message);
                  reject(response.data);
                }
            }
          } else {
            Toast("请求错误");
          }
        },
        complete() {
          uni.stopPullDownRefresh(); //  停止当前下拉
          Loading && HideLoading()
          let end =Date.now();
          console.warn(`响应接口${url}，参数${JSON.stringify(sendData)},耗时`, `${end - start}ms`)
        }
      });
      MQ.push({
        url,
        data: JSON.stringify(sendData),
        request: requestTask
      })
    });
  }

// post 请求方式，以及约束数据类型的使用
  static Post<T>(api_url: string, sendData: object, parameter: PARAMETER = {}):Promise<T>{
    const { dataAll,  verifyData, loading } = parameter
    return RequestHttp.req(api_url, sendData, "POST", loading ?? false, dataAll ?? false,  verifyData ?? false) as Promise<T>
  }

  static Get<T extends HTTPSEND>(api_url: string, sendData: object, parameter: PARAMETER = {}) {
    const { dataAll,  verifyData, loading } = parameter
    return RequestHttp.req(api_url, sendData, "GET", loading ?? false, dataAll ?? false,  verifyData ?? false)
  }

  static PostAll<T>(api_url: string, sendData: object, parameter: PARAMETER = {}) {
    const { dataAll,  verifyData, loading } = parameter
    return RequestHttp.req(api_url, sendData, "POST", loading ?? false, dataAll ?? false,  verifyData ?? false) as Promise<T>
  }
  /**
   * uniapp 多图上传方法
   * api_url,地址
   * filePath,文件数组,
   * formData, 额外的参数
   * name NodeJS 服务获取的KEY
   */
  static UpdateFile(api_url: string, files: any, formData?: {}, name = "fileList", Loading = false,) {

    let url = `${import.meta.env.VITE_APP_BASE_AliOSSSTS}${api_url}`;

    return new Promise((resolve, reject) => {
      Loading && ShowLoading()
      // #ifdef MP-WEIXIN
      const wxupload = (img: any) => {
        return new Promise((resolve,) => {
          uni.uploadFile({
            //参数可查看官方文档
            url,
            filePath: img,
            name: 'file',
            header: {
              "Content-Type": "multipart/form-data",
              "accept": 'application/json'
            },
            success: (res: unknown) => {
              resolve(res)
            }
          })
        })
      }


      const all = files.map((file: any) => wxupload(file.url || file.path))
      const statusCode: any[] = [], allFiledata: any[] = [];
      ShowLoading('上传中...')
      Promise.all(all).then(res => {
        try {
          for (let i = 0; i < res.length; i++) {
            const element: any = res[i];
            const alldata = JSON.parse(element.data);
            allFiledata.push(...alldata.data)
            statusCode.push(element.statusCode)
            statusCode.push(alldata.code)
          }
          console.log('回显数据', allFiledata, statusCode);
          if (statusCode.every(i => i === 200)) {
            Loading && HideLoading()
            resolve(allFiledata)
          } else {
            Toast('上传文件失败')
            reject([]);
          }
        } catch (error) {
          Toast('上传文件失败')
          reject(error);
        }
        uni.hideLoading()
      }).catch(() => {
        uni.hideLoading()
        Toast('上传文件失败')
      })
      //#endif

      // #ifndef  MP-WEIXIN
      // 需条件编译的代码
      ShowLoading('上传中...')
      const uploadTask = uni.uploadFile({
        url,
        files,
        name,
        formData,
        success: (uploadFileRes: { statusCode: any; data: any; }) => {
          let { statusCode, data } = uploadFileRes;
          let dataType = '';
          try {
            dataType = typeof JSON.parse(data)
          } catch (e) {
            dataType = 'string'
          }

          if (statusCode === 200) {
            Loading && HideLoading()
            let setverData = dataType === 'object' ? JSON.parse(data) : data;
            setverData.code === 200 ? resolve(setverData.data) : Toast(setverData.msg);
          } else {
            Toast(data.msg);
          }
        },
        file(err: Error) {
          reject(err);
        },
        complete() {
          uni.hideLoading()
        }
      });
      //#endif


      uploadTask.onProgressUpdate((res: any) => {
        console.log("上传进度" + res.progress);
        console.log("已经上传的数据长度" + res.totalBytesSent);
        console.log("预期需要上传的数据总长度" + res.totalBytesExpectedToSend);
      });
    });
  }


  /**
   * 成功数据
   * @param successData 后端返回体
   * @returns 
   */
  static success(successData: { data?: any; code?: string | number; result?: any; message?: string | null; }) {
    const {
      code,
      result,
      data,
      message
    } = successData;
    if (code && RequestHttp.successCode.includes(code)) { // 主要业务服务状态码成功
      return result || data
    } else if (code === 1) {  // 可根据不同需求定义不同业务状态码 次要业务返回code状态
      return successData.data
    } else if (code === -103) { // 根据不同状态码，返回所有内容
      return successData
    } else {
      message && Toast(message)
    }
  }
}

export const Http = RequestHttp.req
export const Post = RequestHttp.Post
export const Get = RequestHttp.Get

export const PostAll = RequestHttp.PostAll
export const UpdateFile = RequestHttp.UpdateFile
